package variabilitysmelldetection.measurement.models;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;

import variabilitysmelldetection.measurement.astvisitors.ClassVisitor;
import variabilitysmelldetection.measurement.measures.Measure;
import de.ovgu.featureide.core.IFeatureProject;


public class Project {
	private String name;
	private String projectPath;
	private String featuresPath;
	
	@SuppressWarnings("rawtypes")
	private Map<Class, Measure> measures;
	
	private List<ComponentItem> componentItems;
	
	private List<String> featuresNames;
	
	
	@SuppressWarnings("rawtypes")
	public Project(String name, String path){
		this.name      = name;
		featuresPath   = path;
		measures       = new LinkedHashMap<Class, Measure>();
		componentItems = new ArrayList<ComponentItem>();
		featuresNames  = new ArrayList<String>(); 
	}
	
	public Project(IFeatureProject project){
		this(project.getProjectName(), project.getSourcePath());
		projectPath  = project.getProject().getLocation().toString();
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getProjectPath() {
		return projectPath;
	}

	public String getFeaturesPath() {
		return featuresPath;
	}

	public void setFeaturesPath(String path) {
		this.featuresPath = path;
	}

	public Collection<Measure> getMeasures() {
		return measures.values();
	}

	public void addMeasure(Measure m) {
		measures.put(m.getClass(), m);		
	}
	
	public Measure getMeasure(Class<?> measure) {
		return measures.get(measure);
	}
	
	public List<ComponentItem> getClassItems() {
		if (componentItems.isEmpty()) {
			populateClassItems();
		}
		return componentItems;
	}

	private void populateClassItems(){
		List<File> jaks = new ArrayList<File>();
		
		File featuresDir = new File(featuresPath);
		String[] features = featuresDir.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return new File(dir, name).isDirectory();
			}
		});
		
		for (String featureName : features) {
			featuresNames.add(featureName);
			
			String path = featuresDir.getAbsoluteFile()+"/"+featureName;
			getJakFiles(featureName, path, jaks);
		}
	}
	
	private void getJakFiles(String featureName, String path, List<File> jaks){
		File mainFolder = new File(path);
		if (mainFolder.isDirectory()) {
			File[] subfolders = mainFolder.listFiles();
			for (File subfolder : subfolders) {
				if (subfolder.isDirectory()) {
					getJakFiles(featureName, subfolder.getAbsolutePath(), jaks);
				}
			}
			File[] jakFiles = mainFolder.listFiles(new FilenameFilter() {
				@Override
				public boolean accept(File dir, String name) {
					return new File(dir, name).getName().endsWith(".jak");
				}
			});
			for (File jak : jakFiles) {
				ComponentItem componentItem = createClassItem(featureName, jak);
				String filePath = jak.getAbsolutePath();
				filePath = filePath.substring(filePath.indexOf("features/"));
				componentItem.setPath(filePath);
				componentItems.add(componentItem);
			}
		}
	}
	
	private ComponentItem createClassItem(String featureName, File jak){

		final StringBuffer buffer = new StringBuffer();
		
		ComponentItem componentItem = new ComponentItem(featureName, jak.getName());
		try {
			final BufferedReader in = new BufferedReader(new FileReader(jak));
			String line = null;
			while (null != (line = in.readLine())) {
				if (line.contains("layer")) {
					line = line.replace("layer", "package");
				}
				if (line.contains("refines")) {
					componentItem.setRefinement(true);
					line = line.replace("refines", "");
				}
				if (line.contains("interface")) {
					componentItem.setInterface(true);
				}				
				buffer.append(line).append("\n");
			}
			in.close();
			
			componentItem.setSource(buffer.toString());
			CompilationUnit unit = (CompilationUnit)componentItem.getCompilationUnit(ASTParser.K_COMPILATION_UNIT);
			ClassVisitor classVisitor = new ClassVisitor(componentItem);
			unit.accept(classVisitor);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return componentItem;
	}

	public String getFieldsAndMeasuresNames() {
		StringBuilder dados = new StringBuilder();
		dados.append("project");
		dados.append(";");
		for (Measure m : getMeasures()) {
			dados.append(m.getAcronym());
			dados.append(";");
		}
		
		return dados.toString();
	}
	
	public String toCSV() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(getName());
		buffer.append(";");
		for (Measure m : getMeasures()) {
			buffer.append(NumberFormat.getNumberInstance().format(m.getValue()));
			buffer.append(";");
		}
		
		return buffer.toString();
	}

	public List<String> getFeaturesNames() {
		return featuresNames;
	}
}
